/*******************************************************************************
 * Copyright (c) 2012-2017 Codenvy, S.A.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *   Codenvy, S.A. - initial API and implementation
 *******************************************************************************/
package org.eclipse.che.plugin.docker.compose.yaml.deserializer;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static java.lang.String.format;

/**
 * Deserializer of environment section of Docker compose file.
 *
 * @author Dmytro Nochevnov
 */
public class EnvironmentDeserializer extends JsonDeserializer<Map<String, String>> {

    public static final String ARRAY_ITEM_VALUE_DIVIDER  = "=";
    public static final String UNSUPPORTED_VALUE_MESSAGE = "Unsupported value '%s'.";

    @Override
    public Map<String, String> deserialize(JsonParser jsonParser, DeserializationContext ctxt) throws IOException, JsonProcessingException {
        Object environment = jsonParser.readValueAs(Object.class);

        /* Parse dictionary in view of:
           "environment:
             key1: value1
             key2: value2"
        */
        if (environment instanceof Map) {
            return (Map<String, String>) environment;
        }

        /* Parse array in view of:
           "environment:
             - key1=value1
             - key2=value2"
        */
        try {
            if (environment instanceof List) {
                return parseArrayEnvironment((List<String>) environment);
            }
        } catch (IllegalArgumentException ie) {
            throw ctxt.mappingException(ie.getMessage());

        } catch (Exception e) {
            throw ctxt.mappingException(format(UNSUPPORTED_VALUE_MESSAGE, environment));
        }

        // work around empty environment
        if (environment instanceof String) {
            if (((String) environment).isEmpty()) {
                return new HashMap<>();
            }

            throw ctxt.mappingException(format(UNSUPPORTED_VALUE_MESSAGE, environment));
        }

        /* Work around unsupported type of environment content, for example, 'Boolean' in case of content:
           "environment:
             true"
        */
        throw ctxt.mappingException(format("Unsupported type '%s'.", environment.getClass()));
    }

    /**
     * Convert list [key1=value1, key2=value2] into Map<String, String>{ key1: value1, key2: value2 }.
     *
     * @param environment
     *          list form of compose environment to parse
     * @return map of key/value which are divided by "=" sign in item.
     * @throws IllegalArgumentException if there is no "=" sign in environment item, or if there is empty key in item
     */
    private Map<String, String> parseArrayEnvironment(List<String> environment) throws IllegalArgumentException {
        Map<String, String> map = new HashMap<>();
        for (String item : environment) {
            int valueDividerIndex = item.indexOf(ARRAY_ITEM_VALUE_DIVIDER);
            if (valueDividerIndex < 1) {
                throw new IllegalArgumentException(format(UNSUPPORTED_VALUE_MESSAGE, item));
            }

            String key = item.substring(0, valueDividerIndex);
            String value = item.substring(valueDividerIndex + 1, item.length());

            map.put(key, value);
        }

        return map;
    }
}
